package user

import (
	"bytes"
	"cross-shard-channel/common"
	"cross-shard-channel/ledger"
	"encoding/json"
	"github.com/eywa-protocol/bls-crypto/bls"
	"io/ioutil"
	"net/http"
	"time"
)

// 定义回复请求的函数
func InitCloseRequest(client *http.Client, cid int) bool {
	// 初始化基本参数
	var requestObject InitClose
	var responseObject InitCloseResponse
	name := "/init-close"

	requestObject.Cid = cid

	// get local information about the channel
	ch := UN.GetChannelFromNode(cid)
	ch.Lock()
	advIP := ch.AdvIP
	ch.Unlock()

	// generate request body
	bodyStr, err := json.Marshal(requestObject)
	if err != nil {
		println(err.Error())
		return false
	}
	bodyBuffer := bytes.NewBuffer(bodyStr)
	// do request
	url := advIP + name
	request, _ := http.NewRequest("POST", url, bodyBuffer)
	request.Header.Set("Content-type", "application/json")
	response, err := client.Do(request)
	// error process
	if err != nil {
		println(err.Error())
		return false
	} else if response.StatusCode != 200 {
		println("response error")
		return false
	}
	// 模拟网络通信延迟
	time.Sleep(time.Duration(NET_DELAY) * time.Millisecond)

	// 解析回复
	responseBody, _ := ioutil.ReadAll(response.Body)
	err = json.Unmarshal(responseBody, &responseObject)
	if err != nil {
		println("response unmarshal error")
	}

	if responseObject.Ack {
		// println("Close Init Success")
		return true
	} else {
		return false
	}

}

// 定义回复请求的函数
func CloseCreateRequest(client *http.Client, cid int) bool {
	// 初始化基本参数
	var requestObject CloseCreate
	var responseObject CloseCreateResponse
	name := "/close-create"

	// get local information about the channel
	UN.Lock()
	myMainPri := UN.Pri
	myMainPub := UN.Pub
	UN.Unlock()

	ch := UN.GetChannelFromNode(cid)
	ch.Lock()
	advIP := ch.AdvIP

	myChPub := ch.MyChPub
	myChPri := ch.MyChPri
	advChPub := ch.AdvChPub
	myNotifyPri := ch.MyNotifyPri

	myChBalance := ch.MyBalance
	advChBalance := ch.AdvBalance

	createUTXO := ch.CreateUTXO
	notifyUTXOA := ch.NotifyUTXOA
	notifyUTXOB := ch.NotifyUTXOB

	chType := ch.Type

	ch.Unlock()

	// close 交易构造，这个交易是给对方的
	inputs := []common.UTXO{createUTXO, notifyUTXOA, notifyUTXOB}
	outputA := common.UTXO{
		PublicKey: myChPub,
		Balance:   myChBalance,
	}
	outputB := common.UTXO{
		PublicKey: advChPub,
		Balance:   advChBalance,
	}
	outputs := []common.UTXO{outputA, outputB}
	closeTx := common.GenerateTransactionByUTXO(inputs, outputs, 0)
	outputB.Tx_id = closeTx.TxId

	// generate corresponding signature
	// 构造commit交易
	myMainSig := closeTx.Sign(myMainPri)
	myChSig := closeTx.Sign(myChPri)
	myNotifySig := closeTx.Sign(myNotifyPri)

	// generate request object
	requestObject.Cid = cid
	requestObject.MainSigA = myMainSig
	requestObject.NotifySigA = myNotifySig
	requestObject.ChSigA = myChSig
	requestObject.TxClose = *closeTx

	// generate request body
	bodyStr, err := json.Marshal(requestObject)
	if err != nil {
		println(err.Error())
		return false
	}
	bodyBuffer := bytes.NewBuffer(bodyStr)
	// do request
	url := advIP + name
	request, _ := http.NewRequest("POST", url, bodyBuffer)
	request.Header.Set("Content-type", "application/json")
	response, err := client.Do(request)
	// error process
	if err != nil {
		println(err.Error())
		return false
	} else if response.StatusCode != 200 {
		println("response error")
		return false
	}
	// 模拟网络通信延迟
	time.Sleep(time.Duration(NET_DELAY) * time.Millisecond)

	// 解析回复
	responseBody, _ := ioutil.ReadAll(response.Body)
	err = json.Unmarshal(responseBody, &responseObject)
	if err != nil {
		println("response unmarshal error")
	}

	// 构造close交易
	var sig0 bls.Signature
	var sig1 bls.Signature
	var sig2 bls.Signature

	if chType == 0 {
		sig0 = myChSig.Aggregate(responseObject.ChSigB)
		sig1 = myMainSig.Aggregate(responseObject.NotifySigB)
		sig2 = responseObject.MainSigB.Aggregate(myNotifySig)
	} else {
		sig0 = responseObject.ChSigB.Aggregate(myChSig)
		sig1 = responseObject.NotifySigB.Aggregate(myMainSig)
		sig2 = myNotifySig.Aggregate(responseObject.MainSigB)
	}
	closeTx.Sigs = []bls.Signature{sig0, sig1, sig2}
	if !closeTx.Verify() {
		println("Close Create Error: the close tx construct fail!")
	}

	// 构建退款交易
	refundInputs := []common.UTXO{closeTx.Output[0]}
	refundOutputs := []common.UTXO{common.UTXO{
		PublicKey: myMainPub,
		Tx_id:     nil,
		Balance:   myChBalance,
	}}
	refundTx := common.GenerateTransactionByUTXO(refundInputs, refundOutputs, 0)
	refundTx.Sigs = []bls.Signature{refundTx.Sign(myChPri)}
	if !refundTx.Verify() {
		println("Close ERROR: the last refund tx construct fail!")
	}

	// 交易执行等待结果
	txRes := CallLedgerTransactionExe(ch.TxClose, "tx_close")
	if !txRes {
		println("ERROR: ledger refuse transaction create")
		return false
	}

	// 模拟区块链共识延迟
	time.Sleep(time.Duration(ledger.TX_DELAY) * time.Millisecond)

	// 修改通道状态
	ch.Lock()
	ch.TxClose = *closeTx
	ch.TxRefunds = append(ch.TxRefunds, *refundTx)
	ch.Unlock()

	// println("Close Create Success")
	return true
}
